package me.goldze.mvvmhabit.net;

import android.content.Context;
import android.os.Build;
import android.text.TextUtils;
import android.util.Log;

import com.google.gson.Gson;
import com.google.gson.GsonBuilder;
import com.google.gson.JsonDeserializationContext;
import com.google.gson.JsonDeserializer;
import com.google.gson.JsonElement;
import com.google.gson.JsonObject;
import com.google.gson.JsonParseException;
import com.google.gson.TypeAdapterFactory;
import com.google.gson.internal.bind.ObjectTypeAdapter;
import com.google.gson.reflect.TypeToken;

import java.io.File;
import java.lang.reflect.Field;
import java.lang.reflect.Type;
import java.net.Proxy;
import java.security.cert.CertificateException;
import java.util.Collections;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.concurrent.TimeUnit;

import javax.net.ssl.HostnameVerifier;
import javax.net.ssl.SSLContext;
import javax.net.ssl.SSLSession;
import javax.net.ssl.SSLSocketFactory;
import javax.net.ssl.TrustManager;
import javax.net.ssl.X509TrustManager;

import me.goldze.mvvmhabit.net.gson.DataTypeAdapter;
import me.goldze.mvvmhabit.net.gson.DoubleDefault_0;
import me.goldze.mvvmhabit.net.gson.IntegerDefault_0;
import me.goldze.mvvmhabit.net.gson.LongDefault_0;
import me.goldze.mvvmhabit.utils.MapTypeAdapter;
import me.goldze.mvvmhabit.utils.ResponseDataTypeAdaptor;
import okhttp3.Cache;
import okhttp3.CacheControl;
import okhttp3.Interceptor;
import okhttp3.OkHttpClient;
import retrofit2.Retrofit;
import retrofit2.adapter.rxjava2.RxJava2CallAdapterFactory;
import retrofit2.converter.gson.GsonConverterFactory;

public class RetrofitClient {

    private static final int DEFAULT_TIMEOUT = 30;
    private static OkHttpClient okHttpClient;
    public static String baseUrl = "http://jiuyouhui.cn";//正式环境
//    public static String baseUrl = "http://mall.jyh99.cn";//测试环境
    private static Context mContext;
    private static Retrofit retrofit;
    private Cache cache = null;
    private File httpCacheDirectory;
    private static volatile RetrofitClient instance = null;
    public long time;

    public static RetrofitClient getInstance(Context context) {
        if (instance == null) {
            synchronized (RetrofitClient.class) {
                if (instance == null) {
                    instance = new RetrofitClient(context);
                }
            }
        }
        return instance;
    }

    private RetrofitClient(Context context) {

        this(context, baseUrl, null);
    }

    private RetrofitClient(Context context, String url) {
        this(context, url, null);
    }

    private RetrofitClient(final Context context, String url, Map<String, String> headers) {
        mContext = context;
        if (TextUtils.isEmpty(url)) {
            url = baseUrl;
        }
        try {
            initHttpClint(context, url);
        } catch (Exception e) {
            Log.e("OKHttp", "Could not create http cache", e);
        }


    }

    private void initHttpClint(Context context, String finalUrl) {
        if (httpCacheDirectory == null) {
            httpCacheDirectory = new File(mContext.getCacheDir(), "tamic_cache");
        }
        if (cache == null) {
            cache = new Cache(httpCacheDirectory, 10 * 1024 * 1024);
        }

        if (Build.VERSION.SDK_INT > 22) {
            okHttpClient = new OkHttpClient.Builder()
                    .cookieJar(new NovateCookieManger(context))
                    .addInterceptor(new BaseInterceptor(context))
                    .addInterceptor(new LoggingInterceptor())
                    .connectTimeout(DEFAULT_TIMEOUT, TimeUnit.SECONDS)
                    .writeTimeout(DEFAULT_TIMEOUT, TimeUnit.SECONDS)
                    .readTimeout(DEFAULT_TIMEOUT * 10, TimeUnit.SECONDS)//由于上传视频等待时间有点长 所有这里设置长一点的响应时间
//                    .proxy(Proxy.NO_PROXY)
                    .build();
        } else {
            //当API小于22时，因为服务端证书不受信任，Okhttp底层TCP三次握手会话中断。因此需要手动设置信任全部证书。可能存在一定安全风险。
            okHttpClient = gettUnsafeOkHttpClient().newBuilder()
                    .cookieJar(new NovateCookieManger(context))
                    .addInterceptor(new BaseInterceptor(context))
                    .addInterceptor(new LoggingInterceptor())
                    .connectTimeout(DEFAULT_TIMEOUT, TimeUnit.SECONDS)
                    .writeTimeout(DEFAULT_TIMEOUT, TimeUnit.SECONDS)
                    .readTimeout(DEFAULT_TIMEOUT * 10, TimeUnit.SECONDS)//由于上传视频等待时间有点长 所有这里设置长一点的响应时间
//                    .proxy(Proxy.NO_PROXY)
                    .build();
        }
//        Gson gson = new GsonBuilder()
//                .registerTypeAdapter(Integer.class, new IntegerDefault_0())
//                .registerTypeAdapter(int.class, new IntegerDefault_0())
//                .registerTypeAdapter(Double.class, new DoubleDefault_0())
//                .registerTypeAdapter(double.class, new DoubleDefault_0())
//                .registerTypeAdapter(Long.class, new LongDefault_0())
//                .registerTypeAdapter(long.class, new LongDefault_0())
//                .registerTypeAdapter(new TypeToken<Map<String,Object>>(){}.getType(),new DataTypeAdapter())
//                .serializeNulls()//序列化为null对象
//                .setPrettyPrinting()
//                .disableHtmlEscaping()
//                .create();
        Gson gson = new GsonBuilder()
                .registerTypeAdapterFactory(ResponseDataTypeAdaptor.FACTORY)
                .setPrettyPrinting()
                .disableHtmlEscaping()
                .create();
        GsonConverterFactory gsonConverterFactory = GsonConverterFactory.create(gson);
        retrofit = new Retrofit.Builder()
                .client(okHttpClient)
                .addConverterFactory(gsonConverterFactory)
//                .addConverterFactory(MyGsonConverterFactory.create(GsonClass.buildGson()))
                .addCallAdapterFactory(RxJava2CallAdapterFactory.create())
                .baseUrl(finalUrl)
                .build();
    }

    private OkHttpClient gettUnsafeOkHttpClient() {
        try {
            // Create a trust manager that does not validate certificate chains
            final TrustManager[] trustAllCerts = new TrustManager[]{
                    new X509TrustManager() {
                        @Override
                        public void checkClientTrusted(java.security.cert.X509Certificate[] chain, String authType) throws CertificateException {
                        }

                        @Override
                        public void checkServerTrusted(java.security.cert.X509Certificate[] chain, String authType) throws CertificateException {
                        }

                        @Override
                        public java.security.cert.X509Certificate[] getAcceptedIssuers() {
                            return new java.security.cert.X509Certificate[]{};
                        }
                    }
            };

            // Install the all-trusting trust manager
            final SSLContext sslContext = SSLContext.getInstance("SSL");
            sslContext.init(null, trustAllCerts, new java.security.SecureRandom());
            // Create an ssl socket factory with our all-trusting manager
            final SSLSocketFactory sslSocketFactory = sslContext.getSocketFactory();

            OkHttpClient.Builder builder = new OkHttpClient.Builder();
            builder.sslSocketFactory(sslSocketFactory);
            builder.hostnameVerifier(new HostnameVerifier() {
                @Override
                public boolean verify(String hostname, SSLSession session) {
                    return true;
                }
            });

            OkHttpClient okHttpClient = builder.build();
            return okHttpClient;
        } catch (Exception e) {
            throw new RuntimeException(e);
        }
    }

    /**
     * create you ApiService
     * Create an implementation of the API endpoints defined by the {@code service} interface.
     */
    public <T> T create(final Class<T> service) {
        if (service == null) {
            throw new RuntimeException("Api service is null!");
        }
        return retrofit.create(service);
    }
}
